home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / TERMINAL / SRCS / MAIN.C < prev    next >
Text File  |  1990-12-11  |  19KB  |  819 lines

  1. /*
  2.     Terminal 2.0
  3.     "Main.c"
  4. */
  5.  
  6. #ifdef THINK_C
  7. #include "MacHeaders"
  8. #endif
  9. #ifdef applec
  10. #pragma load ":(Objects):MacHeadersMPW"
  11. #pragma segment Main
  12. #endif
  13.  
  14. #include "Text.h"
  15. #include "Main.h"
  16. #include "Strings.h"
  17. #include "Utilities.h"
  18. #include "Document.h"
  19. #include "File.h"
  20. #include "Options.h"
  21. #include "Scroll.h"
  22. #include "Serial.h"
  23. #include "FormatStr.h"
  24. #include "Macros.h"
  25. #include "CancelDialog.h"
  26. #include "Crc.h"
  27.  
  28. #define CAN        0x18    /* Cntrl-X */
  29.  
  30. #define STACKSPACE    0x4000    /* We need a least 16K stack (default is 8K on
  31.                                 a Mac Plus and 24K on a Mac IIcx) */
  32.  
  33. /* ----- Globals ------------------------------------------------------- */
  34.  
  35. SysEnvRec        Mac;                /* Machine information */
  36. Boolean            WNE;                /* WaitNextEvent() flag */
  37. Boolean            Background;            /* In background flag */
  38. DocumentPeek    TerminalWindow;        /* Terminal window */
  39. Options            Settings;            /* Current options */
  40. Byte            EmptyStr[] = "";    /* Often needed empty string */
  41. OSType            TEXT = 'TEXT';        /* Text file type */
  42. Handle            KCHR;                /* 'KCHR' resource */
  43. Types            Application;        /* Application information */
  44. Boolean            Abort = FALSE;        /* Abort flag */
  45. Boolean            Busy = FALSE;        /* Transmit in progress flag */
  46. short            SendFileRef = 0;    /* Send file reference number */
  47. Boolean            Sending = FALSE;    /* Sending in progress */
  48. short            Transfer = 0;        /* File transfer in progress */
  49. Configuration    Config;                /* Configuration parameters */
  50. Boolean            Control_X = FALSE;    /* Control-X abort flag */
  51. Handle            MacrosText = 0;        /* Macros text */
  52. Boolean            MFmemory;            /* MultiFinder temporary memory */
  53. Boolean            DTR = FALSE;        /* Current state of DTR output */
  54. #ifdef USECTB
  55. Boolean            CTB;                /* Communications Tool Box flag */
  56. #endif
  57.  
  58. /* ----- Display error alert ------------------------------------------- */
  59.  
  60. void Error(
  61.     register short code,
  62.     register Byte *text)
  63. {
  64.     Byte message[256];
  65.  
  66.     FormatStr(message, (Byte *)"\p%s%i %s", MyString(STR_M, M_ERROR),
  67.         code, text);
  68.     if (TerminalWindow) {
  69.         SysBeep(1);
  70.         MakeMessage(TerminalWindow, message);
  71.     } else {
  72.         ParamText(message, EmptyStr, EmptyStr, EmptyStr);
  73.         CenterDialog('ALRT', ALRT_ERROR);
  74.         Alert(ALRT_ERROR, 0);
  75.     }
  76. }
  77.  
  78. /* ----- See if window is document window ------------------------------ */
  79.  
  80. Boolean IsDocument(register WindowPtr window)
  81. {
  82.     return window && ((WindowPeek)window)->windowKind == userKind;
  83. }
  84.  
  85. /* ----- See if window is system window -------------------------------- */
  86.  
  87. Boolean IsSystem(register WindowPtr window)
  88. {
  89.     return window && ((WindowPeek)window)->windowKind < 0;
  90. }
  91.  
  92. /* ----- Quit ---------------------------------------------------------- */
  93.  
  94. static void Terminate(void)
  95. {
  96.     register short err;
  97.     register Byte *name;
  98.     short r;
  99.     long count;
  100.     Point position;
  101.  
  102.     SerialDropDTR(Settings.dropDTR);
  103.     SerialClose();
  104.     if (SendFileRef)            /* Close send file if necessary */
  105.         FSClose(SendFileRef);
  106.     if (TerminalWindow->file)    /* Close capture file if necessary */
  107.         TextCapture(0);
  108.     DisposPtr(TerminalWindow->buf.text);
  109.     position = topLeft(((GrafPtr)TerminalWindow)->portRect);
  110.     SetPort((GrafPtr)TerminalWindow);
  111.     LocalToGlobal(&position);
  112.     if (position.h != Settings.terminalWindow.h ||
  113.             position.v != Settings.terminalWindow.v ) {
  114.         Settings.terminalWindow = position;
  115.         Settings.dirty = TRUE;
  116.     }
  117.     DisposeWindow((WindowPtr)TerminalWindow);
  118.     if (MacrosText)
  119.         DisposHandle(MacrosText);
  120.  
  121.     /* Save options if necessary */
  122.  
  123.     if (Settings.dirty) {
  124.         if ((err = OpenFile(Settings.scriptVolume,
  125.                 Settings.scriptDirectory,
  126.                 name = MyString(STR_G, G_SETTINGS), &r)) == fnfErr) {
  127.             if (!(err = CreateFile(Settings.scriptVolume,
  128.                     Settings.scriptDirectory, name,
  129.                     Application.signature, Application.otype)))
  130.                 err = OpenFile(Settings.scriptVolume,
  131.                         Settings.scriptDirectory,
  132.                     name, &r);
  133.         }
  134.         if (!err) {
  135.             Settings.version = SETTINGS;
  136.             Settings.crc = CalcCRC((Byte *)&Settings + sizeof(short),
  137.                 sizeof(Settings) - sizeof(short), 0);
  138.             count = sizeof(Settings);
  139.             err = FSWrite(r, &count, (Ptr)&Settings);
  140.             FSClose(r);
  141.             FlushVol(0, Mac.sysVRefNum);
  142.         }
  143.         if (err)
  144.             Error(err, EmptyStr);
  145.     }
  146.     ExitToShell();
  147. }
  148.  
  149. /* ----- Adjust menus -------------------------------------------------- */
  150.  
  151. static void AdjustMenus(void)
  152. {
  153.     register MenuHandle menu;
  154.     register Boolean empty =
  155.         TerminalWindow->buf.newChar == TerminalWindow->buf.firstChar;
  156.  
  157.     menu = GetMHandle(FILE);
  158.     if (Transfer) {
  159.         DisableItem(menu, SCREEN);
  160.         DisableItem(menu, CAPTURE);
  161.         DisableItem(menu, SEND);
  162.         switch (Transfer) {
  163.             case Transfer_Rx:
  164.                 EnableItem(menu, RECEIVE);    /* To cancel receive */
  165.                 DisableItem(menu, TRANSMIT);
  166.                 break;
  167.             case Transfer_Tx:
  168.                 DisableItem(menu, RECEIVE);
  169.                 EnableItem(menu, TRANSMIT);    /* To cancel transmit */
  170.                 break;
  171.             case Transfer_B:
  172.                 DisableItem(menu, RECEIVE);
  173.                 DisableItem(menu, TRANSMIT);
  174.         }
  175.         DisableItem(menu, MAKE);
  176.         DisableItem(menu, EXTRACT);
  177.         DisableItem(menu, KISS);
  178.         DisableItem(menu, QUIT);
  179.     } else {
  180.         if (empty)
  181.             DisableItem(menu, SCREEN);
  182.         else
  183.             EnableItem(menu, SCREEN);
  184.         EnableItem(menu, CAPTURE);
  185.         EnableItem(menu, SEND);
  186.         EnableItem(menu, RECEIVE);
  187.         EnableItem(menu, TRANSMIT);
  188.         EnableItem(menu, MAKE);
  189.         EnableItem(menu, EXTRACT);
  190.         EnableItem(menu, KISS);
  191.         EnableItem(menu, QUIT);
  192.     }
  193.  
  194.     menu = GetMHandle(EDIT);
  195.     if (Transfer) {
  196.         DisableItem(menu, RESET);
  197.         EnableItem(menu, SHOWPW);
  198.         DisableItem(menu, DEBLOCK);
  199.     } else {
  200.         if (empty)
  201.             DisableItem(menu, RESET);
  202.         else
  203.             EnableItem(menu, RESET);
  204.         DisableItem(menu, SHOWPW);
  205.         EnableItem(menu, DEBLOCK);
  206.     }
  207.     if (DTR) {
  208.         EnableItem(menu, DTRDROP);
  209.         DisableItem(menu, DTRASSERT);
  210.     } else {
  211.         DisableItem(menu, DTRDROP);
  212.         EnableItem(menu, DTRASSERT);
  213.     }
  214.     if (IsSystem(FrontWindow())) {
  215.         EnableItem(menu, UNDO);
  216.         EnableItem(menu, CUT);
  217.         EnableItem(menu, COPY);
  218.         EnableItem(menu, PASTE);
  219.         EnableItem(menu, CLEAR);
  220.     } else {
  221.         long offset;
  222.         DisableItem(menu, UNDO);
  223.         DisableItem(menu, CUT);
  224.         DisableItem(menu, COPY);
  225.         if (Transfer || GetScrap(0, TEXT, &offset) <= 0)
  226.             DisableItem(menu, PASTE);
  227.         else
  228.             EnableItem(menu, PASTE);
  229.         DisableItem(menu, CLEAR);
  230.     }
  231.  
  232.     menu = GetMHandle(OPTIONS);
  233.     if (Transfer)
  234.         DisableItem(menu, 0);
  235.     else
  236.         EnableItem(menu, 0);
  237.  
  238.     menu = GetMHandle(SCRIPT);
  239.     if (Transfer)
  240.         DisableItem(menu, 0);
  241.     else
  242.         EnableItem(menu, 0);
  243.  
  244.     menu = GetMHandle(MACRO);
  245.     if (Transfer)
  246.         DisableItem(menu, 0);
  247.     else
  248.         EnableItem(menu, 0);
  249. }
  250.  
  251. /* ----- Handle menu commands ------------------------------------------ */
  252.  
  253. static void DoMenuCommand(
  254.     register long menuResult,
  255.     short options)
  256. {
  257.     register short menuItem;
  258.     Str255 daName;
  259.  
  260.     menuItem = LoWrd(menuResult);
  261.     switch(HiWrd(menuResult)) {
  262.         case APPLE:
  263.             switch(menuItem) {
  264.                 case ABOUT:
  265.                     About(options);
  266.                     UnloadSeg(About);
  267.                     break;
  268.                 default:
  269.                     GetItem(GetMHandle(APPLE), menuItem, &daName);
  270.                     OpenDeskAcc(&daName);
  271.                     break;
  272.             }
  273.             break;
  274.         case FILE:
  275.             switch(menuItem) {
  276.                 case SCREEN:        /* Save screen buffer */
  277.                     SaveBuffer(options);
  278.                     break;
  279.                 case CAPTURE:        /* Capture to text file */
  280.                     TextCapture(options);
  281.                     break;
  282.                 case SEND:            /* Send text file */
  283.                     HiliteMenu(0);
  284.                     SendText();
  285.                     return;
  286.                 case RECEIVE:        /* Receive file */
  287.                     HiliteMenu(0);
  288.                     FileReceive();
  289.                     return;
  290.                 case TRANSMIT:        /* Transmit file */
  291.                     HiliteMenu(0);
  292.                     FileTransmit();
  293.                     return;
  294.                 case MAKE:            /* Make MacBinary file */
  295.                     Make();
  296.                     break;
  297.                 case EXTRACT:        /* Extract from MacBinary file */
  298.                     Extract();
  299.                     break;
  300.                 case KISS:            /* Kiss script file file */
  301.                     Kiss(options);
  302.                     break;
  303.                 case QUIT:
  304.                     HiliteMenu(0);
  305.                     Terminate();
  306.                     return;
  307.             }
  308.             break;
  309.         case EDIT:
  310.             if (!SystemEdit(menuItem-1)) {
  311.                 switch(menuItem) {
  312.                     case PASTE:        /* Send TEXT from scrap */
  313.                         HiliteMenu(0);
  314.                         SendScrap();
  315.                         return;
  316.                     case RESET:        /* Clear capture buffer */
  317.                         ClearBuffer();
  318.                         break;
  319.                     case SHOWPW:    /* Show progress window */
  320.                         SelectCancelDialog();
  321.                         break;
  322.                     case DEBLOCK:    /* Deblock send after XOFF/CTS */
  323.                         Sending = FALSE;
  324.                         SerialAbort();
  325.                         break;
  326.                     case DTRDROP:    /* Drop DTR */
  327.                         SerialDTR(FALSE);
  328.                         break;
  329.                     case DTRASSERT:    /* Assert DTR */
  330.                         SerialDTR(TRUE);
  331.                         break;
  332.                     case CTSCHECK:    /* Check CTS */
  333.                         {
  334.                             Byte s[80];
  335.                             MakeMessage(TerminalWindow,
  336.                                 FormatStr(s, (Byte *)"\pCTS=%i", SerialCTS()));
  337.                         }
  338.                         break;
  339.                 }
  340.             }
  341.             break;
  342.         case OPTIONS:
  343.             switch(menuItem) {
  344.                 case PORT:
  345.                     PortOptions();
  346.                     UnloadSeg(PortOptions);
  347.                     break;
  348.                 case TEXTSEND:
  349.                     SendOptions();
  350.                     UnloadSeg(SendOptions);
  351.                     break;
  352.                 case TERMINAL:
  353.                     TerminalOptions();
  354.                     UnloadSeg(TerminalOptions);
  355.                     break;
  356.                 case OTHER:
  357.                     OtherOptions();
  358.                     UnloadSeg(OtherOptions);
  359.                     break;
  360.                 case TRANSFER:
  361.                     ProtocolOptions();
  362.                     UnloadSeg(ProtocolOptions);
  363.                     break;
  364.                 case XYOPTIONS:
  365.                     XYOptions();
  366.                     UnloadSeg(XYOptions);
  367.                     break;
  368.                 case ZOPTIONS:
  369.                     ZOptions();
  370.                     UnloadSeg(ZOptions);
  371.                     break;
  372.             }
  373.             break;
  374.         case SCRIPT:
  375.             HiliteMenu(0);
  376.             if (menuItem == DOSCRIPT) {
  377.                 if (RunScript(0, 0, 0, menuItem))
  378.                     Terminate();
  379.                 return;
  380.             }
  381.             if (DoMenuScript(menuItem))
  382.                 Terminate();
  383.             return;
  384.         case MACRO:
  385.             if (menuItem == DOMACRO) {
  386.                 short err;
  387.                 if (err = LoadMacros(0, 0, 0))
  388.                     Error(err, EmptyStr);
  389.             } else {
  390.                 HiliteMenu(0);
  391.                 DoMacro(menuItem, (options & (optionKey | shiftKey)) != 0);
  392.                 return;
  393.             }
  394.     }
  395.     HiliteMenu(0);
  396. }
  397.  
  398. /* ----- Handle new event ---------------------------------------------- */
  399.  
  400. #define SuspendResume    1
  401. #define ResumeMask        1
  402.  
  403. void DoEvent(register EventRecord *event)
  404. {
  405.     register short part;
  406.     register Byte key;            /* ASCII key code */
  407.     register short code;        /* Virtual key code */
  408.     long state;                    /* Used by KeyTrans() */
  409.     WindowPtr window;
  410.  
  411.     switch(event->what) {
  412.         case mouseDown:
  413.             switch(part = FindWindow(event->where, &window)) {
  414.                 case inMenuBar:
  415.                     AdjustMenus();
  416.                     DoMenuCommand(MenuSelect(event->where),
  417.                         event->modifiers);
  418.                     break;
  419.                 case inSysWindow:
  420.                     SystemClick(event, window);
  421.                     break;
  422.                 case inContent:
  423.                     if (window != FrontWindow())
  424.                         SelectWindow(window);
  425.                     else {
  426.                         if (IsDocument(window)) {
  427.                             SetPort(window);
  428.                             GlobalToLocal(&event->where);
  429.                             DocumentClick((DocumentPeek)window,
  430.                                 event->where, event->modifiers);
  431.                         }
  432.                     }
  433.                     break;
  434.                 case inDrag:
  435.                     DragWindow(window, event->where, &QD(screenBits.bounds));
  436.                     break;
  437.                 case inGoAway:
  438.                     /* Quit if close box clicked in document window */
  439.                     if (TrackGoAway(window, event->where)) {
  440.                         if (IsDocument(window)) {
  441.                             if (Transfer)
  442.                                 SysBeep(1);
  443.                             else
  444.                                 Terminate();
  445.                         }
  446.                         if (IsSystem(window))
  447.                             CloseDeskAcc(((WindowPeek)window)->windowKind);
  448.                     }
  449.                     break;
  450.                 }
  451.                 break;
  452.             case keyDown:
  453.             case autoKey:
  454.                 if (IsSystem(FrontWindow()))
  455.                     break;
  456.                 key = event->message & charCodeMask;
  457.                 /* Menu commands are not available if the command key
  458.                 is used as control key */
  459.                 if (Settings.ctrl != 2 && (event->modifiers & cmdKey)) {
  460.                     if (event->what == keyDown) {
  461.                         AdjustMenus();
  462.                         DoMenuCommand(MenuKey(key), event->modifiers);
  463.                     }
  464.                     break;
  465.                 }
  466.                 /* Ignore key strokes if file transfer is in progress,
  467.                 or if terminal window is not frontmost */
  468.                 if (Transfer || !IsDocument(FrontWindow()))
  469.                     break;
  470.                 /* Use option key as control key, if this option is set */
  471.                 if (Settings.ctrl == 1 && (event->modifiers & optionKey) && KCHR) {
  472.                     code = (event->message >> 8) & 0x7F;
  473.                     if (event->modifiers & shiftKey)
  474.                         code |= 0x0200;
  475.                     state = 0;
  476.                     LoadResource(KCHR);
  477.                     if (*KCHR)
  478.                         key = KeyTrans(*KCHR, code, &state) & 0x1F;
  479.                 } else
  480.                     /* Use option key as control key, if this option is set */
  481.                     if (Settings.ctrl == 2 && (event->modifiers & cmdKey))
  482.                         key &= 0x1F;
  483.                 NewKey(key);
  484.                 break;
  485.             case activateEvt:
  486.                 if (IsDocument((WindowPtr)event->message))
  487.                     ActivateDocument((DocumentPeek)event->message,
  488.                         event->modifiers & activeFlag);
  489.                 break;
  490.             case updateEvt:
  491.                 if (IsDocument((WindowPtr)event->message)) {
  492.                     BeginUpdate((WindowPtr)event->message);
  493.                     DrawDocument((DocumentPeek)event->message, 0);
  494.                     DrawControls((WindowPtr)event->message);
  495.                     EndUpdate((WindowPtr)event->message);
  496.                 }
  497.                 break;
  498.             case diskEvt:
  499.                 if (HiWord(event->message) != noErr) {
  500.                     static Point where = { 80, 80 };
  501.                     DIBadMount(where, event->message);
  502.                 }
  503.                 break;
  504.             case app4Evt:
  505.                 if (((unsigned long)event->message >> 24)==SuspendResume) {
  506.                     window = FrontWindow();
  507.                     if (event->message & ResumeMask) {
  508.                         Background = FALSE;
  509.                         if (IsDocument(window)) {
  510.                             HiliteWindow(window, TRUE);
  511.                             ActivateDocument((DocumentPeek)window, TRUE);
  512.                         }
  513.                     } else {
  514.                         Background = TRUE;
  515.                         if (IsDocument(window)) {
  516.                             HiliteWindow(window, FALSE);
  517.                             ActivateDocument((DocumentPeek)window, FALSE);
  518.                         }
  519.                     }
  520.                 }
  521.                 break;
  522.         }
  523. }
  524.  
  525. /* ----- Check for ctrl-X (abort sending) ------------------------------ */
  526.  
  527. static void AbortCheck(
  528.     register Byte *buffer,
  529.     register long count)
  530. {
  531.     static short can = 0;
  532.  
  533.     while (count--) {
  534.         *buffer &= 0x7F;            /* Strip bit 7 */
  535.         if (*buffer++ == CAN) {        /* Check for control-X */
  536.             if (can == 4) {            /* 5th consecutive control-X */
  537.                 SerialAbort();
  538.                 Sending = FALSE;
  539.                 Control_X = TRUE;
  540.             } else
  541.                 ++can;
  542.         } else
  543.             can = 0;
  544.     }
  545. }
  546.  
  547. /* ----- Strip BS characters from string ------------------------------- */
  548.  
  549. static void StripBS(register Byte *s)
  550. {
  551.     register Byte t[256];
  552.     register Byte *p, *q;
  553.     register Byte c;
  554.     register short n;
  555.  
  556.     n = *s;
  557.     p = s + 1;
  558.     q = t + 1;
  559.     while (n--) {
  560.         if ((c = *p++) == Settings.backspace) {
  561.             if (q == t + 1)
  562.                 break;
  563.             --q;
  564.         } else
  565.             *q++ = c;
  566.     }
  567.     *t = q - (t + 1);
  568.     memcpy(s, t, *t + 1);
  569. }
  570.  
  571. /* ----- Quick event check --------------------------------------------- */
  572.  
  573. void CheckEvents(void)
  574. {
  575.     register long count;
  576.     register Byte buffer[256];
  577.     EventRecord event;
  578.  
  579.     /* Make sure events and receive buffer are checked at least once */
  580.  
  581.     do {
  582.  
  583.         /* While transmitting check Mac events */
  584.  
  585.         do {
  586.             if (WNE)
  587.                 WaitNextEvent(everyEvent, &event, 0, 0);
  588.             else {
  589.                 SystemTask();
  590.                 GetNextEvent(everyEvent, &event);
  591.             }
  592.             DoEvent(&event);
  593.         } while (Busy);
  594.  
  595.         /* If transmission finished see if something received */
  596.  
  597.         if (count = SerialRead(buffer, sizeof(buffer))) {
  598.             AbortCheck(buffer, count);
  599.             if (Settings.echo)
  600.                 SerialSend(buffer, count, &Busy);
  601.             if (Settings.save)
  602.                 NewCharacters(buffer, count, FALSE);
  603.         }
  604.  
  605.     } while (Busy);
  606.     /* Only return if no more transmission is going on */
  607. }
  608.  
  609. /* ----- Universal main event loop ------------------------------------- */
  610.  
  611. short Loop(
  612.     register long timeout,    /* Timeout in ticks (0 for no timeout) */
  613.     Byte *string,            /* Prompt string (1) or line (2) */
  614.     register short mode)    /* 1: wait for prompt, 2: return next line */
  615. {
  616.     register long count;        /* Number of characters received */
  617.     register short code = -1;    /* Return code */
  618.     Byte buffer[256];            /* Receive buffer */
  619.     EventRecord event;
  620.     register Byte *s, *p, *max;
  621.     register Byte c;
  622.  
  623.     if (timeout)
  624.         timeout += Ticks;
  625.     Abort = FALSE;
  626.     if (string) {
  627.         switch (mode) {
  628.             case 1:    /* Prompt mode */
  629.                 if (*string)
  630.                     max = string + *string;
  631.                 else
  632.                     mode = 0;
  633.                 break;
  634.             case 2:    /* Line mode */
  635.                 max = string + 255;
  636.                 break;
  637.         }
  638.         s = string + 1;
  639.     } else
  640.         mode = 0;
  641.  
  642.     /* Make sure events and receive buffer are checked at least once */
  643.  
  644.     do {
  645.  
  646.         /* Check for and handle Mac events */
  647.  
  648.         do {
  649.             if (WNE)
  650.                 WaitNextEvent(everyEvent, &event, 0, 0);
  651.             else {
  652.                 SystemTask();
  653.                 GetNextEvent(everyEvent, &event);
  654.             }
  655.             DoEvent(&event);
  656.         } while (Busy);
  657.  
  658.         /* Check receive buffer */
  659.  
  660.         if (code < 0 && (count = SerialRead(buffer, sizeof(buffer)))) {
  661.             AbortCheck(buffer, count);
  662.             if (Settings.echo)
  663.                 SerialSend(buffer, count, &Busy);
  664.             if (Settings.save)
  665.                 NewCharacters(buffer, count, TRUE);
  666.             switch (mode) {
  667.                 case 1:    /* Prompt mode */
  668.                     p = buffer;
  669.                     while (count--)
  670.                         if ((*p++ & 0x7F) == *s) {
  671.                             if (s >= max) {
  672.                                 code = FINE;
  673.                                 break;    /* Prompt received */
  674.                             }
  675.                             s++;
  676.                         } else
  677.                             s = string + 1;
  678.                     break;
  679.                 case 2:    /* Line mode */
  680.                     p = buffer;
  681.                     while (count--) {
  682.                         c = *p++ & 0x7F;
  683.                         if (c == '\015') {
  684.                             *string = s - string - 1;
  685.                             StripBS(string);
  686.                             code = FINE;
  687.                             break;    /* Command line received */
  688.                         }
  689.                         if (s <= max)
  690.                             *s++ = c;
  691.                     }
  692.                     break;
  693.             } /* switch (mode) */
  694.         } /* if (count) */
  695.  
  696.         /* Check abort or timeout */
  697.  
  698.         if (Abort)
  699.             code = CANCEL;
  700.         else if (timeout && Ticks > timeout)
  701.             code = TIMEOUT;
  702.  
  703.     } while (code < 0 || Busy);
  704.     /* Only return if no transmission is going on */
  705.     Abort = TRUE;
  706.     return code;
  707. }
  708.  
  709. /* ----- Universal main event loop ------------------------------------- */
  710.  
  711. short LoopBuffer(
  712.     register long timeout,    /* Timeout in ticks (0 for no timeout) */
  713.     register Byte *buffer,    /* Buffer supplied by caller */
  714.     register long limit)    /* Size of buffer */
  715. {
  716.     register long count;        /* Number of characters received */
  717.     register short code = -1;    /* Return code */
  718.     EventRecord event;
  719.  
  720.     if (timeout)
  721.         timeout += Ticks;
  722.     Abort = FALSE;
  723.  
  724.     /* Make sure events and receive buffer are checked at least once */
  725.  
  726.     do {
  727.  
  728.         /* Check for and handle Mac events */
  729.  
  730.         do {
  731.             if (WNE)
  732.                 WaitNextEvent(everyEvent, &event, 0, 0);
  733.             else {
  734.                 SystemTask();
  735.                 GetNextEvent(everyEvent, &event);
  736.             }
  737.             DoEvent(&event);
  738.         } while (Busy);
  739.  
  740.         /* Check receive buffer */
  741.  
  742.         if ((count = SerialCheck()) >= limit) {
  743.             SerialFastRead(buffer, limit);
  744.             AbortCheck(buffer, limit);
  745.             if (Settings.echo)
  746.                 SerialSend(buffer, limit, &Busy);
  747.             if (Settings.save)
  748.                 NewCharacters(buffer, limit, TRUE);
  749.             code = FINE;    /* Buffer received */
  750.         }
  751.  
  752.         /* Check abort or timeout */
  753.  
  754.         if (Abort)
  755.             code = CANCEL;
  756.         else if (timeout && Ticks > timeout)
  757.             code = TIMEOUT;
  758.  
  759.     } while (code < 0 || Busy);
  760.     /* Only return if no transmission is going on */
  761.     Abort = TRUE;
  762.     return code;
  763. }
  764.  
  765. /* ----- Crash --------------------------------------------------------- */
  766.  
  767. pascal void Crash(void)
  768. {
  769.     ExitToShell();
  770. }
  771.  
  772. /* ----- Main ---------------------------------------------------------- */
  773.  
  774. void main(void)
  775. {
  776. #ifdef applec
  777.     void _DataInit(void);
  778.     UnloadSeg((Ptr)_DataInit);
  779. #endif
  780.     SetApplLimit(CurStackBase - STACKSPACE);
  781.     MaxApplZone();
  782.     if (Init())
  783.         return;
  784.     UnloadSeg(Init);
  785.     LoadMacros (Settings.scriptVolume, Settings.scriptDirectory,
  786.         MyString(STR_G, G_MACROS));
  787.  
  788.     /* Check if script selected from desktop */
  789.  
  790.     {
  791.         short message, count, i;
  792.         AppFile file;
  793.  
  794.         CountAppFiles(&message, &count);
  795.         if (message == appOpen)
  796.             for (i = 1; i <= count; ++i) {
  797.                 GetAppFiles (i, &file);
  798.                 if (file.fType == TEXT &&
  799.                         CheckSuffix((Byte *)file.fName,
  800.                             MyString(STR_G, G_SUFFIX))) {
  801.                     if (RunScript(file.vRefNum, 0,
  802.                             (Byte *)file.fName, DOSCRIPT))
  803.                         Terminate();
  804.                     break;
  805.                 }
  806.             }
  807.     }
  808.  
  809.     /* Check for startup script */
  810.  
  811.     if (Settings.startName[0] && RunScript(Settings.startVolume,
  812.             Settings.startDirectory, Settings.startName, DOSCRIPT))
  813.         Terminate();
  814.     for (;;) {
  815.         SetWTitle((WindowPtr)TerminalWindow, MyString(STR_G, G_TERMINAL));
  816.         Loop(0, 0, 0);
  817.     }
  818. }
  819.